package com.cjd.common.utils

import android.text.TextUtils
import okhttp3.ResponseBody
import java.io.*
import java.nio.channels.FileChannel
import java.text.DecimalFormat

/**
 * @Author chenjidong
 * @email 374122600@qq.com
 * created 2016/1/31.
 * description
 */
object FileUtil {

    fun createFolder(path: String): String? {
        val outfile = File(path)
        // 如果文件不存在，则创建一个新文件
        return if (!outfile.exists())
            if (outfile.mkdirs()) path else null
        else
            path
    }

    /**
     * 写对象到文件中。
     *
     * @param outFile
     * @param obj
     */
    fun writeObject(outFile: String, obj: Any) {

        try {
            val out = ObjectOutputStream(
                BufferedOutputStream(FileOutputStream(outFile))
            )
            out.writeObject(obj)
            out.close()
        } catch (e: Exception) {
            System.err.println(e)
        }

    }

    /**
     * 读取对象
     *
     * @param filePath
     * @return
     */
    fun readObject(filePath: String): Any? {
        val inFile = File(filePath)
        var o: Any? = null
        try {
            val `in` = ObjectInputStream(
                BufferedInputStream(FileInputStream(inFile))
            )
            o = `in`.readObject()
            `in`.close()
        } catch (e: Exception) {
            System.err.println(e)
        }

        return o
    }

    /**
     * 获取文件夹大小
     *
     * @param file File实例
     * @return long 单位为B
     * @throws Exception
     */
    @Throws(Exception::class)
    fun getFolderSize(file: File): Long {
        var size: Long = 0
        val fileList = file.listFiles()
        fileList?.let {
            for (i in it.indices) {
                if (it[i].isDirectory) {
                    size += getFolderSize(it[i])
                } else {
                    size += it[i].length()
                }
            }
        }

        return size// 1M = 1048576;
    }

    /**
     * 文件大小单位换算
     *
     * @param length
     * @return
     */
    fun changeUnit(length: Long): String {
        val df = DecimalFormat("###.##")
        var sizeLong: Double = length.toDouble()
        if (sizeLong < 1024) {
            return "${sizeLong}B"
        } else {
            sizeLong /= 1024f
        }
        if (sizeLong < 1024) {
            return "${df.format(sizeLong)}KB"
        } else {
            sizeLong /= 1024f
        }
        if (sizeLong < 1024) {
            return "${df.format(sizeLong)}MB"
        } else {
            sizeLong /= 1024f
        }
        if (sizeLong < 1024) {
            return "${df.format(sizeLong)}GB"
        } else {
            sizeLong /= 1024f
        }
        if (sizeLong < 1024) {
            return "${df.format(sizeLong)}TB"
        } else
            return "无穷大"
    }

    /**
     * 删除指定目录下文件及目录
     *
     * @param deleteThisPath
     * @param filePath
     * @return
     */
    @Throws(IOException::class)
    fun deleteFolderFile(filePath: String, deleteThisPath: Boolean) {
        if (!TextUtils.isEmpty(filePath)) {
            val file = File(filePath)

            if (file.isDirectory) {// 处理目录
                val files = file.listFiles()
                for (i in files!!.indices) {
                    deleteFolderFile(files[i].absolutePath, true)
                }
            }
            if (deleteThisPath) {
                if (!file.isDirectory) {// 如果是文件，删除
                    file.delete()
                } else {// 目录
                    if (file.listFiles()!!.size == 0) {// 目录下没有文件或者目录，删除
                        file.delete()
                    }
                }
            }
        }
    }

    /**
     * stream 写入文件  带进度回调
     * @param simpleName 默认使用当前activity 类名 ，监听activity 声明周期  null 表示不控制强制中断
     * @param body okhttp 回调
     * @param path 保存路径
     * @param callback 下载进度回调
     * tips：请勿在 主线程使用
     */
    fun writeStream2File(
        simpleName: String?,
        body: ResponseBody,
        path: String,
        callback: ((percent: Int) -> Unit)? = null
    ) {
        var inputStream: InputStream? = null
        var fileOutputStream: FileOutputStream? = null
        val newFile = File(path)
        try {
            val totalLength = body.contentLength()
            var writeLength = 0L
            inputStream = body.byteStream()

            if (newFile.parentFile == null || !newFile.parentFile.exists()) {
                newFile.parentFile.mkdirs()
            }
            fileOutputStream = FileOutputStream(newFile)

            val data = ByteArray(2048)

            var length = inputStream.read(data)
            var nowInterrupt = ActivityLifecycleCallbacksUtil.isNowInterrupt(simpleName)
            while (length != -1) {
                nowInterrupt = ActivityLifecycleCallbacksUtil.isNowInterrupt(simpleName)
                if (nowInterrupt)
                    break
                fileOutputStream.write(data, 0, length)
                writeLength += length

                var percent: Int = (100 * writeLength / totalLength).toInt()
                LogUtils.d("--->$percent")
                if (percent >= 99)
                    percent = 99
                callback?.invoke(percent)

                length = inputStream.read(data)
            }
            if (nowInterrupt) {
                newFile.delete()
            } else {
                fileOutputStream.flush()
                callback?.invoke(100)
            }

        } catch (e: Exception) {
            LogUtils.e(e)
            newFile?.delete()
            callback?.invoke(-1)
        } finally {
            try {
                inputStream?.close()
                fileOutputStream?.close()
            } catch (e: Exception) {
                LogUtils.e(e)
                newFile?.delete()
                callback?.invoke(-2)
            }

        }
    }


    fun transferFile(fromFile: File, targetFile: File, delFrom: Boolean = false): Boolean {
        lateinit var inputChannel: FileChannel
        lateinit var outputChannel: FileChannel
        try {
            inputChannel = FileInputStream(fromFile).channel
            outputChannel = FileOutputStream(targetFile).channel
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size())
        } catch (e: IOException) {
            return false
        } finally {
            try {
                inputChannel?.close()
                outputChannel?.close()
                if (delFrom)
                    fromFile.delete()
            } catch (e: IOException) {
                return false
            }
        }

        return true
    }
}